/**
****************************************************************
* @file felica.c
*
* @brief  关于felica协议一些基本的底层驱动接口
*
* @author 
*
* 
****************************************************************
*/ 
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "define.h"
#include "nfc663.h"
#include "felica.h"
#include <string.h>
#include "rfid.h"
#include "timer.h"

int pcd_request_c(u8 *pSysCode, u8 bReqCode, u8 bSlot, u8 bRate, u8 *pResponse)
{
	u32 XDATA wTimeOutUs;
	int status = MI_OK;
	transceive_buffer XDATA *pi;
	
	pi = &mf_com_data;

#if (NFC_DEBUG)
	printf("REQC:\n");
#endif
	switch (bSlot)
    {
	    case PHPAL_FELICA_NUMSLOTS_1:
	    case PHPAL_FELICA_NUMSLOTS_2:
	    case PHPAL_FELICA_NUMSLOTS_4:
	    case PHPAL_FELICA_NUMSLOTS_8:
	    case PHPAL_FELICA_NUMSLOTS_16:
	        wTimeOutUs = PHPAL_FELICA_SW_RESP_TIME_A_US + ((bSlot + 1) * PHPAL_FELICA_SW_RESP_TIME_B_US);
			if(read_reg(TxModeReg) & PHHAL_HW_BIT_212KBPS)
			{
				wTimeOutUs -= 226;	
			}
			else
			{
				wTimeOutUs -= 113;
			}
	        break;
	    default:
			printf("SLOT_ERROR = %02x\n", (u16)bSlot);
	        return USER_ERROR;//PH_ADD_COMPCODE(PH_ERR_INVALID_PARAMETER, PH_COMP_PAL_FELICA);
    }
	pcd_set_reqc_tmo(wTimeOutUs, bRate);
	
	if(bSlot > PHPAL_FELICA_NUMSLOTS_1)		//配置多重接收
	{
		write_reg(RxModeReg, (read_reg(RxModeReg) | PHHAL_HW_BIT_RXMULTIPLE));
	}	

	mf_com_data.mf_command = PCD_TRANSCEIVE;
	mf_com_data.mf_length = 6;
	mf_com_data.mf_data[0] = mf_com_data.mf_length;
	mf_com_data.mf_data[1] = PHPAL_FELICA_SW_CMD_REQC;
	mf_com_data.mf_data[2]	= pSysCode[0];
	mf_com_data.mf_data[3] = pSysCode[1];
	mf_com_data.mf_data[4] = bReqCode;
	mf_com_data.mf_data[5] = bSlot;
	status = pcd_com_transceive(pi);

	if(bSlot > PHPAL_FELICA_NUMSLOTS_1)
	{
		write_reg(RxModeReg, (read_reg(RxModeReg) & (~PHHAL_HW_BIT_RXMULTIPLE)));
	}	
	if (status != MI_OK)
	{
		return status;
	}
	if((mf_com_data.mf_data[0] != mf_com_data.mf_length / 8) 
		|| (mf_com_data.mf_data[0] != PHPAL_FELICA_ATQC_LENGTH)
		|| (mf_com_data.mf_data[1] != PHPAL_FELICA_SW_RSP_REQC))
    { 
        return PROTOCOL_ERR;
    }
	memcpy(pResponse, mf_com_data.mf_data, PHPAL_FELICA_ATQC_LENGTH); 

	return MI_OK;	
}

int pcd_req_resp(u8 *pIdmPMm, u8 *pMode)
{
	int XDATA status;
	transceive_buffer XDATA *pi;
	
	pi = &mf_com_data;

#if (NFC_DEBUG)
		printf("REQUEST RESPONSE:\n");
#endif
	pcd_set_felica_tmo(0, pIdmPMm[11]);
	mf_com_data.mf_command = PCD_TRANSCEIVE;
	mf_com_data.mf_length = 10;
	mf_com_data.mf_data[0] = mf_com_data.mf_length;	
	mf_com_data.mf_data[1] = PHPAL_FELICA_SW_CMD_REQ_RESP;
	memcpy(&mf_com_data.mf_data[2], pIdmPMm, PHPAL_FELICA_IDM_LENGTH);
	
	status = pcd_com_transceive(pi);

	if (status != MI_OK)
	{
		return status;
	}

   /* Check length */
	if((mf_com_data.mf_data[0] != mf_com_data.mf_length / 8) 
		|| (mf_com_data.mf_data[0] != FELICA_REQUEST_RESPONSE_RSP_LEN + 1)
		|| (mf_com_data.mf_data[1] != FELICA_REQUEST_RESPONSE_RES))
    { 
        return PROTOCOL_ERR;
    }

	*pMode = mf_com_data.mf_data[FELICA_REQUEST_RESPONSE_RSP_LEN];
	return MI_OK;		
}

int pcd_req_service(u8 *pIdmPMm, 
						 u8  bTxNumServices, 
                         u8 *pTxServiceList, 
                         u8 *pRxNumServices, 
                         u8 *pRxServiceList
                         )
{
	int XDATA status = MI_OK;	
	transceive_buffer XDATA *pi;

	pi = &mf_com_data;

#if (NFC_DEBUG)
	printf("REQUEST SERVICE:\n");
#endif
	pcd_set_felica_tmo(bTxNumServices, pIdmPMm[10]);
	
	mf_com_data.mf_command = PCD_TRANSCEIVE;
	mf_com_data.mf_length = 11 + (bTxNumServices * 2);
	mf_com_data.mf_data[0] = mf_com_data.mf_length;
	mf_com_data.mf_data[1] = PHPAL_FELICA_SW_CMD_REQ_SERVICE;
	memcpy(&mf_com_data.mf_data[2], pIdmPMm, PHPAL_FELICA_IDM_LENGTH);
	mf_com_data.mf_data[10] = bTxNumServices;
	memcpy(&mf_com_data.mf_data[11], pTxServiceList, (bTxNumServices * 2));
	
	status = pcd_com_transceive(pi);

	if (status != MI_OK)
	{
		return status;
	}

   /* Check length */
	if((mf_com_data.mf_data[0] != mf_com_data.mf_length / 8) 
		|| (mf_com_data.mf_data[0] != (11 + (bTxNumServices * 2)))
		|| (mf_com_data.mf_data[1] != FELICA_REQUEST_SERVIVE_RES))
    { 
        return PROTOCOL_ERR;
    }
	*pRxNumServices = mf_com_data.mf_data[10];
	memcpy(pRxServiceList, &mf_com_data.mf_data[11], *pRxNumServices * 2);
	
	return MI_OK;			
}

int pcd_read_without_encryption(u8 *pIdmPMm, 
								         u8  bNumServices, 
								         u8 *pServiceList, 
								         u8  bTxNumBlocks, 
								         u8 *pBlockList,
								         u8  bBlockListLength,
								         u8 *pRxNumBlocks,
								         u8 *pBlockData,
								         u8 *pStatusFlag
								         )
{
	int XDATA status = MI_OK;	
	transceive_buffer XDATA *pi;

	pi = &mf_com_data;

#if (NFC_DEBUG)
	printf("FELICA READ:\n");
#endif	
	pcd_set_felica_tmo(bNumServices, pIdmPMm[13]);

	mf_com_data.mf_command = PCD_TRANSCEIVE;
	mf_com_data.mf_length = 12 + (2 * bNumServices) + (bBlockListLength);		//(2 * bTxNumBlocks) <= bBlockListLength <= (3 * bTxNumBlocks)
	mf_com_data.mf_data[0] = mf_com_data.mf_length;
	mf_com_data.mf_data[1] = PHPAL_FELICA_SW_CMD_READ;
	memcpy(&mf_com_data.mf_data[2], pIdmPMm, PHPAL_FELICA_IDM_LENGTH);
	mf_com_data.mf_data[10] = bNumServices;	//number of service 
	memcpy(&mf_com_data.mf_data[11], pServiceList, (2 * bNumServices));
	mf_com_data.mf_data[11 + (2 * bNumServices)] = bTxNumBlocks;	//number of block 
	memcpy(&mf_com_data.mf_data[11 + (2 * bNumServices) + 1], pBlockList, bBlockListLength);
	
	status = pcd_com_transceive(pi);
	
	if (status != MI_OK)
	{
		return status;
	}

   /* Check length */
	if((mf_com_data.mf_data[0] != mf_com_data.mf_length / 8) 
		|| (mf_com_data.mf_data[0] != (13 + (mf_com_data.mf_data[12] * 16)))
		|| (mf_com_data.mf_data[1] != FELICA_READ_WITHOUT_ENCRYPTION_RES))
    { 
        return PROTOCOL_ERR;
    }

	*pRxNumBlocks = mf_com_data.mf_data[12];
	memcpy(pStatusFlag, &mf_com_data.mf_data[10], 2);
	memcpy(pBlockData, &mf_com_data.mf_data[13], (mf_com_data.mf_data[12] * 16));
		
	return MI_OK;	
}

int pcd_write_without_encryption(u8 *pIdmPMm, 
										  u8  bNumServices, 
										  u8 *pServiceList, 
										  u8  bNumBlock, 
										  u8 *pBlockList,
										  u8  bBlockListLength,
										  u8 *pBlockData,
										  u8 *pStatusFlag
										  )
{
	int XDATA status = MI_OK;	 
	transceive_buffer XDATA *pi;

	pi = &mf_com_data;

#if (NFC_DEBUG)
	printf("FELICA WRITE:\n");
#endif	
	pcd_set_felica_tmo(bNumServices, pIdmPMm[14]);

	mf_com_data.mf_command = PCD_TRANSCEIVE;
	mf_com_data.mf_length = 12 + (2 * bNumServices) + (bBlockListLength) + ((16 * bNumBlock));
	mf_com_data.mf_data[0] = mf_com_data.mf_length;
	mf_com_data.mf_data[1] = PHPAL_FELICA_SW_CMD_WRITE;
	memcpy(&mf_com_data.mf_data[2], pIdmPMm, PHPAL_FELICA_IDM_LENGTH);
	mf_com_data.mf_data[10] = bNumServices;	//number of service 
	memcpy(&mf_com_data.mf_data[11], pServiceList, (2 * bNumServices));
	mf_com_data.mf_data[11 + (2 * bNumServices)] = bNumBlock;	//number of block 
	memcpy(&mf_com_data.mf_data[11 + (2 * bNumServices) + 1], pBlockList, bBlockListLength);
	memcpy(&mf_com_data.mf_data[11 + (2 * bNumServices) + 2], pBlockData, (16 * bNumBlock));	

	status = pcd_com_transceive(pi);
	
	if (status != MI_OK)
	{
		return status;
	}

	/* Check length */
	if((mf_com_data.mf_data[0] != mf_com_data.mf_length / 8) 
	 || (mf_com_data.mf_data[0] != (FELICA_WRITE_WITHOUT_ENCRYPTION_RSP_LEN))
	 || (mf_com_data.mf_data[1] != FELICA_WRITE_WITHOUT_ENCRYPTION_RES))
	{ 
		return PROTOCOL_ERR;
	}

	memcpy(pStatusFlag, &mf_com_data.mf_data[10], 2);

	return MI_OK;	
}

int pcd_req_syscode(u8 *pIdmPMm,  u8 *pSysCodeNum, u8 *pSysCodeList)
{
	int XDATA status = MI_OK;   
	transceive_buffer XDATA *pi;

	pi = &mf_com_data;

#if (NFC_DEBUG)
	printf("REQUSET SYSTEM CODE:\n");
#endif	
	pcd_set_felica_tmo(0, pIdmPMm[11]);

	mf_com_data.mf_command = PCD_TRANSCEIVE;
	mf_com_data.mf_length = 10;
	mf_com_data.mf_data[0] = mf_com_data.mf_length;	//LEN
	mf_com_data.mf_data[1] = PHPAL_FELICA_SW_CMD_REQ_SYS_CODE;
	memcpy(&mf_com_data.mf_data[2], pIdmPMm, PHPAL_FELICA_IDM_LENGTH);

	status = pcd_com_transceive(pi);
	
	if (status != MI_OK)
	{
		return status;
	}

	/* Check length */
	if((mf_com_data.mf_data[0] != mf_com_data.mf_length / 8) 
	 || (mf_com_data.mf_data[0] != (11 + (2 * mf_com_data.mf_data[10])))
	 || (mf_com_data.mf_data[1] != FELICA_REQUEST_SYS_CODE_RES))
	{ 
		return PROTOCOL_ERR;
	}

	*pSysCodeNum = mf_com_data.mf_data[10];
	memcpy(pSysCodeList, &mf_com_data.mf_data[11], (2 * (*pSysCodeNum)));

	return MI_OK;		
	
}

void pcd_set_reqc_tmo(u16 wTimeout, u16 wDataRate)
{
    float   XDATA  fTimeoutUs;
    float   XDATA  fTemp;
    u8     XDATA  bRegister;
    u16   XDATA   wPrescaler;
    u16   XDATA   wReload;

    /* Retrieve RxDataRate */
    wDataRate++;

    /* Handle timeout in microseconds */
    fTimeoutUs = (float32_t)wTimeout;

    /* Add timershift to timeout value */
    fTimeoutUs = fTimeoutUs + (PHHAL_HW_TIMER_SHIFT * (PHHAL_HW_ETU_106 / (float32_t)wDataRate));

    /* Add digital delay for Felica */
    fTimeoutUs = fTimeoutUs + PHHAL_HW_FELICA_ADD_DELAY_US;

    /* Max. timeout check */
    if (fTimeoutUs > PHHAL_HW_TIMER_MAX_VALUE_US)
    {
        return;//PH_ADD_COMPCODE(PH_ERR_PARAMETER_OVERFLOW, PH_COMP_HAL);
    }

    /* Calculate the prescaler value */
    /* [timeout[us]  = (1 + 2n) / 13.56] */
    fTemp = (((fTimeoutUs * PHHAL_HW_TIMER_FREQ) / 65535.0f) - 1.0f) / 2.0f;

    /* Except for a special case, the float32_t value will have some commas
    and therefore needs to be "ceiled" */
    if (fTemp > (float)(u16)fTemp)
    {
        wPrescaler = (u16)(fTemp + 1);
    }
    else
    {
        wPrescaler = (u16)fTemp;
    }

    /* Calculate the reload value */
    fTemp = (fTimeoutUs * PHHAL_HW_TIMER_FREQ) / (1.0f + (2.0f * (float)wPrescaler));

    /* Except for a special case, the float32_t value will have some commas
    and therefore needs to be "ceiled" */
    if (fTemp > (float)(u16)fTemp)
    {
        wReload = (u16)(fTemp + 1);
    }
    else
    {
        wReload = (u16)fTemp;
    }

    /* write Prescaler value */
    write_reg(TPrescalerReg, (u8)(wPrescaler & 0xFF));
    bRegister = read_reg(TModeReg);
    bRegister &= (u8)~(u8)PHHAL_HW_MASK_TPRESCALER_HI;
    write_reg(TModeReg, 0x80 | bRegister | (u8)((wPrescaler >> 8) & 0x0F));

    /* write Counter value */
	write_reg(TReloadRegL, (u8)(wReload & 0xFF));
    write_reg(TReloadRegH, (u8)((wReload >> 8) & 0xFF));
}

void pcd_set_felica_tmo(u8 n, u8 Position)
{
	u8 XDATA A, B, E;
	u16 XDATA tmp;

	A = (Position & (BIT0 | BIT1 | BIT2));
	B = (Position & (BIT3 | BIT4 | BIT5)) >> 3;
	E = (Position & (BIT6 | BIT7)) >> 6;
//	printf("a = %02x;b = %02x;e = %02x\n",(u16)A,(u16)B,(u16)E);
	tmp = ((B + 1) * n + (A + 1)) * pow(4, E);
			
	write_reg(TPrescalerReg, (FELICA_FDT_302us/* + TP_dFWT*/) & 0xFF);
	write_reg(TModeReg, BIT7 | (((FELICA_FDT_302us/* + TP_dFWT*/)>>8) & 0xFF));
//	printf("FWT = %u us\n", (u16)(tmp * 302));
    write_reg(TReloadRegL, tmp);//  302 * (Reload + 1)
    write_reg(TReloadRegH, (tmp >> 8));	
}
